/**
 * 
 */
package fr.upvm.lem3.vm3d.domain;

import java.awt.Color;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

/**
 *******************************************************************
 *Channel.java
 *24.02.2012
 *@author Guy Nougouapi
 *******************************************************************
 * *
 * Class for Object that represents a channel. For instance in our program we have the channels listed below:	
 * 		- Phase (DataType byte)
 * 		- Euler1 (DataType float)
 * 		- Euler2 (DataType float)
 * 		- Euler3 (DataType float)
 * 		- MAD	 (DataType float)
 * 		- BC	(DataType short)
 * 		- BS	(DataType short)
 * A channel also have Gradient color, which color each of its single within it data range.
 *******************************************************************
 */
public class Channel<T> {
	
	private String name;		//String name of the channel
	private List<T>dataRange;
	private T lowerLimit;		//Data range's lower and upper limits
	private T upperLimit;
	private String dataType ;			// Concrete data type of this .
	private Color[] color;				//array contents the color of each pixels on the channel
	
	private byte data[][][]; 
	
	public Channel(String name,List<T> list, Color[] col){
		setName(name);
		data = new byte[1][1][1];
		if( !list.isEmpty())
			sortdDataRange(list);			//return a sorted list from low value to bigger value
		this.color = col;
		
	}
	
	public Channel(String name,List<T> list){
		setName(name);
		data = new byte[1][1][1];
		if( !list.isEmpty())
			sortdDataRange(list);
	}
	
	public Channel(){
	}

	/**
	 * 
	 * @param list
	 */
	private void sortdDataRange( List<T> list) {
		
		Collections.sort(list, new Comparator<T>() {
			public int compare(T o1, T o2){
				int res = 0;
				
				String type = o1.getClass().getSimpleName();
				switch (type) {
				case "Byte":
					res=((Byte)o1).compareTo((Byte)o2);
					break;
				case "Short":
					res=((Short)o1).compareTo((Short)o2);
					break;
				case "Float":
					res=((Float)o1).compareTo((Float)o2);
					break;
				case "Integer":
					res=((Integer)o1).compareTo((Integer)o2);
					break;
				case "String":
					res=((String)o1).compareTo((String)o2);
					break;
				case "Double":
					res=((Double)o1).compareTo((Double)o2);
					break;
				case "Boolean":
					res=((Boolean)o1).compareTo((Boolean)o2);
					break;
				default:
					res = 0;
					break;
				}
				return res;
			}
		});
		for ( T l : list){
			getDataRange().add(l);	
		}
		setLowerLimit(getDataRange().get(0));
		setUpperLimit(getDataRange().get(list.size()-1));
		
		dataType= getDataRange().get(0).getClass().getSimpleName();
	}

	
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	/**
	 * @return the dataRange
	 */
	public List<T> getDataRange() {
		if(dataRange == null){
			dataRange = new Vector<T>();
		}
		return dataRange;
	}
	
	/**
	 * @param dataRange the dataRange to set
	 */
	public void setDataRange(T[][][] ranges) {
		 List<T> datas = new Vector<T>();
		 int zdim = ranges.length;						//longueur en Z,
	     int ydim = (ranges[0]).length;					//longueur en Y,
	     int xdim = (ranges[0][0]).length;				//longueur en X,
	     for (int k = 0; k < zdim; k++){
			for (int j = 0; j < ydim; j++)
				for (int i = 0; i < xdim; i++){
						datas.add(ranges[k][j][i]) ;
					}
	     }
		this.setDataRange(datas);
	}
	/**
	 * @param dataRange the dataRange to set
	 */
	public void setDataRange(List<T> dataRange) {
		sortdDataRange(dataRange);
	}
	/**
	 * @return the lowerLimit
	 */
	public T getLowerLimit() {
		return lowerLimit;
	}
	/**
	 * @param lowerLimit the lowerLimit to set
	 */
	public void setLowerLimit(T lowerLimit) {
		this.lowerLimit = lowerLimit;
	}
	/**
	 * @return the upperLimit
	 */
	public T getUpperLimit() {
		return upperLimit;
	}
	/**
	 * @param upperLimit the upperLimit to set
	 */
	public void setUpperLimit(T upperLimit) {
		this.upperLimit = upperLimit;
	}

	/**
	 * @param dataType the dataType to set
	 */
	public void setDataType(Object o) {
		String type = o.getClass().getSimpleName();
		switch (type) {
		case "Byte":
			dataType= "byte";
			break;
		case "Short":
			dataType= "short";
			break;
		case "Float":
			dataType= "flaot";
			break;
		case "Integer":
			dataType= "integer";
			break;
		case "String":
			dataType= "String";
			break;
		case "Double":
			dataType= "double";
			break;
		case "Boolean":
			dataType= "boolean";
			break;
		default:
			dataType = null;
			break;
		}
		
		
	}
	public String getDataType(){
		return dataType ;
	}
	
	public void setData(byte data[][][]) {
		this.data = data;
	}
		
	/**
	 * @return the color
	 */
	public Color[] getColor() {
		return color;
	}
	/**
	 * @param color the color to set
	 */
	public void setColor(Color[] color) {
		this.color = color;
	}
	
	public byte[][][] getData() {
		return data;
	}
	
	//List to all references off the three data of the euler values
	private List<byte[][][]> listDatas;
	public void setDatas(byte[][][] data1, byte[][][] data2, byte[][][] data3) {
		this.listDatas = new Vector<>(3);
		listDatas.add(0, data1);
		listDatas.add(1, data2);
		listDatas.add(1, data3);
	}
	
	public List<byte[][][]> getListDatas(){
		return  this.listDatas;
	}
	/**
	 * 
	 */
	@Override
	public String toString() {
	        return this.getName();
	}
	   
	//Test method
	public static void main(String[] arg){
		List<Integer> list = new Vector<Integer>();
		list.add(1);list.add(2);list.add(3);list.add(100);list.add(4);list.add(5);list.add(4);list.add(10);list.add(00); list.add(100);list.add(200);
		Integer a = new Integer( 1);
		Channel<Integer> channel = new Channel<Integer>("BC", list);
		System.out.println(String.format ("Name: %s, DataType: %s",channel.getName(), channel.getDataType()));
		System.out.println(channel.getLowerLimit());
		System.out.println(channel.getUpperLimit());
	}

	
}
